Regressão Linear com NumPy


In [1]:
import numpy as np
import math
import time

Versão Não Vetorizada

Função para calcular o MSE (Mean Squared Error):

$MSE(\hat{w}) = \frac{1}{N} \sum_{i=1}^N (y_i - \hat{y}_i (x_i))^2$


In [2]:
# y = mx + b
# m is slope, b is y-intercept
def compute_mse(b, m, points):
    totalError = 0
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        totalError += (y - (m * x + b)) ** 2
    return totalError / float(len(points))

Função para fazer uma atualização dos parâmetros no Gradiente Descendente:

$w_0 = w_0 + 2\alpha\sum_{i=1}^N (y_i - (w_0+w_1x_i))$

$w_1 = w_1 + 2\alpha\sum_{i=1}^N x_i(y_i - (w_0+w_1x_i))$


In [24]:
def step_gradient(b_current, m_current, points, learningRate):
    b_gradient = 0
    m_gradient = 0
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        b_gradient += (y - ((m_current * x) + b_current))
        m_gradient += x * (y - ((m_current * x) + b_current))
    new_b = b_current + (2 * learningRate * b_gradient)
    new_m = m_current + (2 * learningRate * m_gradient)
    return [new_b, new_m, b_gradient, m_gradient]

$||\mathbf{w}||_2 = \sqrt{\sum_{j=1}^D w_j^2}$


In [25]:
def norm_2(x):
    c=0
    for i in range(len(x)):
        c += x[i]**2
    return math.sqrt(c)

Função para iterar sobre o gradiente descendente até convergência.


In [39]:
def gradient_descent_runner(points, starting_b, starting_m, learning_rate, epsilon):
    b = starting_b
    m = starting_m
    grad = np.array([np.inf,np.inf])
    i = 0
    while (norm_2(grad)>=epsilon):
        b, m, b_gradient, m_gradient = step_gradient(b, m, points, learning_rate)
        grad = np.array([b_gradient,m_gradient])
        if i % 1000 == 0:
            #print(norm_2(grad))
            print("MSE na iteração {0} é de {1}".format(i,compute_mse(b,m,points)))
        i+= 1
    return [b, m]

In [42]:
points = np.genfromtxt("income.csv", delimiter=",")
learning_rate = 0.0001
initial_b = 0 # initial y-intercept guess
initial_m = 0 # initial slope guess
#num_iterations = 10000
epsilon = 0.5
print("Starting gradient descent at b = {0}, m = {1}, error = {2}".format(initial_b, initial_m, compute_mse(initial_b, initial_m, points)))
print("Running...")
tic = time.time()
[b, m] = gradient_descent_runner(points, initial_b, initial_m, learning_rate, epsilon)
toc = time.time()
print("Gradiente descendente convergiu com w0 = {0}, w1 = {1}, erro = {2}".format(b, m, compute_mse(b, m, points)))
print("Versão vetorizada rodou em: " + str(1000*(toc-tic)) + "ms")


Starting gradient descent at b = 0, m = 0, error = 2946.6344970460195
Running...
MSE na iteração 0 é de 1192.5455472930998
MSE na iteração 1000 é de 72.17883366795655
MSE na iteração 2000 é de 53.761743672145194
MSE na iteração 3000 é de 43.353840547685124
MSE na iteração 4000 é de 37.472105296742534
MSE na iteração 5000 é de 34.14820718311794
MSE na iteração 6000 é de 32.26979916262993
MSE na iteração 7000 é de 31.208269425310196
MSE na iteração 8000 é de 30.60837559451126
MSE na iteração 9000 é de 30.26936238029896
MSE na iteração 10000 é de 30.07777854744394
MSE na iteração 11000 é de 29.96951030457705
MSE na iteração 12000 é de 29.908325536328086
MSE na iteração 13000 é de 29.873748676423904
MSE na iteração 14000 é de 29.854208531465453
MSE na iteração 15000 é de 29.84316596525049
MSE na iteração 16000 é de 29.836925567911035
Gradiente descendente convergiu com w0 = -39.09650898069108, w1 = 5.578663108036406, erro = 29.834653619553226
Versão vetorizada rodou em: 606.8329811096191ms

Versão Vetorizada

$MSE(\hat{w})=\frac{1}{N}(y-\hat{\mathbf{w}}^T\mathbf{x})^T(y-\hat{\mathbf{w}}^T\mathbf{x})$


In [32]:
def compute_mse_vectorized(w,X,Y):
    res = Y - np.dot(X,w)
    totalError = np.dot(res.T,res)
    return totalError / float(len(Y))

In [36]:
def step_gradient_vectorized(w_current,X,Y,learningRate):
    res = Y - np.dot(X,w_current)
    b_gradient = np.sum(res)
    X = X[:,1][:,np.newaxis]
    m_gradient = np.sum(np.multiply(res,X))
    new_w = np.array([(w_current[0] + (2 * learningRate * b_gradient)),
             (w_current[1] + (2 * learningRate * m_gradient))])
    return [new_w,b_gradient,m_gradient]

In [34]:
def gradient_descent_runner_vectorized(starting_w, X,Y, learning_rate, epsilon):
    w = starting_w
    grad = np.array([np.inf,np.inf])
    i = 0
    while (np.linalg.norm(grad)>=epsilon):
        w,b_gradient,m_gradient = step_gradient_vectorized(w, X, Y, learning_rate)
        grad = np.array([b_gradient,m_gradient])
        #print(np.linalg.norm(grad))
        if i % 1000 == 0:
            print("MSE na iteração {0} é de {1}".format(i,compute_mse_vectorized(w, X, Y)))
        i+= 1
    return w

In [41]:
points = np.genfromtxt("income.csv", delimiter=",")
points = np.c_[np.ones(len(points)),points]
X = points[:,[0,1]]
Y = points[:,2][:,np.newaxis]
init_w = np.zeros((2,1))
learning_rate = 0.0001
#num_iterations = 10000
epsilon = 0.5
print("Starting gradient descent at w0 = {0}, w1 = {1}, error = {2}".format(init_w[0], init_w[1], compute_mse_vectorized(init_w, X,Y)))
print("Running...")
tic = time.time()
w = gradient_descent_runner_vectorized(init_w, X,Y, learning_rate, epsilon)
toc = time.time()
print("Gradiente descendente convergiu com w0 = {0}, w1 = {1}, error = {2}".format(w[0], w[1], compute_mse_vectorized(w,X,Y)))
print("Versão vetorizada rodou em: " + str(1000*(toc-tic)) + " ms")


Starting gradient descent at w0 = [ 0.], w1 = [ 0.], error = [[ 2946.63449705]]
Running...
MSE na iteração 0 é de [[ 1192.54554729]]
MSE na iteração 1000 é de [[ 72.17883367]]
MSE na iteração 2000 é de [[ 53.76174367]]
MSE na iteração 3000 é de [[ 43.35384055]]
MSE na iteração 4000 é de [[ 37.4721053]]
MSE na iteração 5000 é de [[ 34.14820718]]
MSE na iteração 6000 é de [[ 32.26979916]]
MSE na iteração 7000 é de [[ 31.20826943]]
MSE na iteração 8000 é de [[ 30.60837559]]
MSE na iteração 9000 é de [[ 30.26936238]]
MSE na iteração 10000 é de [[ 30.07777855]]
MSE na iteração 11000 é de [[ 29.9695103]]
MSE na iteração 12000 é de [[ 29.90832554]]
MSE na iteração 13000 é de [[ 29.87374868]]
MSE na iteração 14000 é de [[ 29.85420853]]
MSE na iteração 15000 é de [[ 29.84316597]]
MSE na iteração 16000 é de [[ 29.83692557]]
Gradiente descendente convergiu com w0 = [-39.09650898], w1 = [ 5.57866311], error = [[ 29.83465362]]
Versão vetorizada rodou em: 490.15092849731445 ms

In [ ]: